package source.events;

import source.view.MainScreen;
import source.events.action.*;
import source.model.*;
import source.model.type.UnitType;
import java.awt.Color;
import source.model.type.GameObjectType;
import source.model.utility.PositionUtility;
/**
 * Class ModelEventListener is the entry point to the game model.  All event that needs to
 * manipulate the model are caught by ModelEventListener.  The ModelEventListener then
 * interprets what kind of ModelEvent was sent, and takes appropriate action to satisfy
 * the request.
 * @author Joe
 *
 */
public class ModelEventListener implements EventListener<ModelEvent> {

	private static final int NORMALSTATE = 0;
	private static final int FREEROAMSTATE = 1;
	private static final int MISSIONSTATE = 2;
	private static final int MISSIONFREEROAMSTATE = 4;
	private DataHandler dh;
	private int melState;
	private UnitMission um;
	
	public ModelEventListener(DataHandler dh)
	{
		this.dh = dh;
		um = null;
		melState = NORMALSTATE;
	}
	/**
	 * eventCallback method gets called by the event handler when a ModelEvent is fired
	 *   The switch statement checks the ModelEventType enum against the type attribute in event
	 */
	public boolean eventCallback(ModelEvent e)
	{
		if(melState == NORMALSTATE)
		{
			return evalNormalState(e);
		}
		
		else if (melState == FREEROAMSTATE)
		{
			return evalFreeRoamState(e);
		}
		
		else if (melState == MISSIONSTATE)
		{
			return evalMissionState(e);
		}
		else if (melState == MISSIONFREEROAMSTATE)
		{
			return evalMissionFreeRoamState(e);
		}
		return false;
	}
	
	private boolean evalFreeRoamState(ModelEvent e)
	{
		switch(ModelEventType.valueOf(e.getType()))
		{
		case MOVEN:
			//MainScreen.writeToConsole(" Move Cursor North", Color.RED);
			MoveCursor mn = new MoveCursor(MoveDirection.N);
			mn.execute(dh);
			return true;
			
		case MOVENW:
			//MainScreen.writeToConsole(" Move Cursor Northwest", Color.RED);
			MoveCursor mnw = new MoveCursor(MoveDirection.NW);
			mnw.execute(dh);
			return true;
		
		case MOVEW:
			//MainScreen.writeToConsole(" Move Cursor West", Color.RED);
			MoveCursor mw = new MoveCursor(MoveDirection.W);
			mw.execute(dh);
			return true;
			
		case MOVESW:
			//MainScreen.writeToConsole(" Move Cursor Southwest", Color.RED);
			MoveCursor msw = new MoveCursor(MoveDirection.SW);
			msw.execute(dh);
			return true;
			
		case MOVES:
			//MainScreen.writeToConsole(" Move Cursor South", Color.RED);
			MoveCursor ms = new MoveCursor(MoveDirection.S);
			ms.execute(dh);
			return true;
			
		case MOVESE:
			//MainScreen.writeToConsole(" Move Cursor Southeast", Color.RED);
			MoveCursor mse = new MoveCursor(MoveDirection.SE);
			mse.execute(dh);
			return true;
			
		case MOVEE:
			//MainScreen.writeToConsole(" Move Cursor East", Color.RED);
			MoveCursor me = new MoveCursor(MoveDirection.E);
			me.execute(dh);
			return true;
		
		case MOVENE:
			//MainScreen.writeToConsole(" Move Cursor Northeast", Color.RED);
			MoveCursor mne = new MoveCursor(MoveDirection.NE);
			mne.execute(dh);
			return true;
			
		case TOGGLEFREEROAM:
			MainScreen.writeToConsole("Entering Normal Mode", Color.RED);
			ResetCursor r = new ResetCursor(e.getPlayerID());
			r.execute(dh);
			melState = NORMALSTATE;
			return true;
			
		case OBSERVE:
			//MainScreen.writeToConsole(" Use Skill: Observe", Color.RED);
			Observe o = new Observe(e.getPlayerID(), dh.getCurrentPosition());
			o.execute(dh);
			ResetCursor ro = new ResetCursor(e.getPlayerID());
			ro.execute(dh);
			melState = NORMALSTATE;
			return true;
			
		case REMOVETRAP:
			ResetCursor rr = new ResetCursor(e.getPlayerID());
			rr.execute(dh);
			melState = NORMALSTATE;
			//MainScreen.writeToConsole(" Use Skill: Remove Trap", Color.RED);
			return true;
			
		case ATTACK:
			//MainScreen.writeToConsole(" Use Skill: Attack", Color.RED);
			Attack a = new Attack(e.getPlayerID(), dh.getCurrentPosition());
			a.execute(dh);
			ResetCursor ra = new ResetCursor(e.getPlayerID());
			ra.execute(dh);
			melState = NORMALSTATE;
			return true;
		}
		
		return false;
	}
	
	private boolean evalMissionFreeRoamState(ModelEvent e)
	{
		switch(ModelEventType.valueOf(e.getType()))
		{
		case MOVEN:
			//MainScreen.writeToConsole(" Move Cursor North", Color.RED);
			MoveCursor mn = new MoveCursor(MoveDirection.N);
			mn.execute(dh);
			return true;
			
		case MOVENW:
			//MainScreen.writeToConsole(" Move Cursor Northwest", Color.RED);
			MoveCursor mnw = new MoveCursor(MoveDirection.NW);
			mnw.execute(dh);
			return true;
		
		case MOVEW:
			//MainScreen.writeToConsole(" Move Cursor West", Color.RED);
			MoveCursor mw = new MoveCursor(MoveDirection.W);
			mw.execute(dh);
			return true;
			
		case MOVESW:
			//MainScreen.writeToConsole(" Move Cursor Southwest", Color.RED);
			MoveCursor msw = new MoveCursor(MoveDirection.SW);
			msw.execute(dh);
			return true;
			
		case MOVES:
			//MainScreen.writeToConsole(" Move Cursor South", Color.RED);
			MoveCursor ms = new MoveCursor(MoveDirection.S);
			ms.execute(dh);
			return true;
			
		case MOVESE:
			//MainScreen.writeToConsole(" Move Cursor Southeast", Color.RED);
			MoveCursor mse = new MoveCursor(MoveDirection.SE);
			mse.execute(dh);
			return true;
			
		case MOVEE:
			//MainScreen.writeToConsole(" Move Cursor East", Color.RED);
			MoveCursor me = new MoveCursor(MoveDirection.E);
			me.execute(dh);
			return true;
		
		case MOVENE:
			//MainScreen.writeToConsole(" Move Cursor Northeast", Color.RED);
			MoveCursor mne = new MoveCursor(MoveDirection.NE);
			mne.execute(dh);
			return true;
			
		case OBSERVE:
			MainScreen.writeToConsole("Observe added to the mission", Color.RED);
			Observe o = new Observe(e.getPlayerID(), dh.getCurrentPosition());
			um.addAction(o);
			melState = MISSIONSTATE;
			return true;
			
		case REMOVETRAP:
			melState = MISSIONSTATE;
			MainScreen.writeToConsole("Remove Trap added to the mission", Color.RED);
			return true;
			
		case ATTACK:
			MainScreen.writeToConsole("Attack added to the mission", Color.RED);
			Attack a = new Attack(e.getPlayerID(), dh.getCurrentPosition());
			um.addAction(a);
			melState = MISSIONSTATE;
			return true;
		}
		return false;
	}
	private boolean evalMissionState(ModelEvent e)
	{
		switch(ModelEventType.valueOf(e.getType()))
		{
			case TOGGLEMISSION:
				MainScreen.writeToConsole("Mission assignment is complete", Color.RED);
				CommitMission cm = new CommitMission(e.getPlayerID(), um);
				cm.execute(dh);
				um = null;
				melState = NORMALSTATE;
				return true;
				
			case SNEAK:
				MainScreen.writeToConsole("Sneak added to the mission", Color.RED);
				Sneak s = new Sneak();
				s.execute(dh);
				return true;
				
			case MOVEN:
				MainScreen.writeToConsole(" Move Unit North added to the mission", Color.RED);
				Move mn = new Move(MoveDirection.N);
				um.addAction(mn);
				return true;
				
			case MOVENW:
				MainScreen.writeToConsole(" Move Unit Northwest added to the mission", Color.RED);
				Move mnw = new Move(MoveDirection.NW);
				um.addAction(mnw);
				return true;
			
			case MOVEW:
				MainScreen.writeToConsole(" Move Unit West added to the mission", Color.RED);
				Move mw = new Move(MoveDirection.W);
				um.addAction(mw);
				return true;
				
			case MOVESW:
				MainScreen.writeToConsole(" Move Unit Southwest added to the mission", Color.RED);
				Move msw = new Move(MoveDirection.SW);
				um.addAction(msw);
				return true;
				
			case MOVES:
				MainScreen.writeToConsole(" Move Unit South added to the mission", Color.RED);
				Move ms = new Move(MoveDirection.S);
				um.addAction(ms);
				return true;
				
			case MOVESE:
				MainScreen.writeToConsole(" Move Unit Southeast added to the mission", Color.RED);
				Move mse = new Move(MoveDirection.SE);
				um.addAction(mse);
				return true;
				
			case MOVEE:
				MainScreen.writeToConsole(" Move Unit East added to the mission", Color.RED);
				Move me = new Move(MoveDirection.E);
				um.addAction(me);
				return true;
			
			case MOVENE:
				MainScreen.writeToConsole(" Move Unit Northeast added to the mission", Color.RED);
				Move mne = new Move(MoveDirection.NE);
				um.addAction(mne);
				return true;
				
			case BUILDBASE:
				MainScreen.writeToConsole("Build Base added to the mission", Color.RED);
				BuildBase bb = new BuildBase(e.getPlayerID());
				um.addAction(bb);
				return true;
				
			case PICKUPITEM:
				MainScreen.writeToConsole("Pickup Item added to the mission", Color.RED);
				PickupItemAction pu = new PickupItemAction();
				um.addAction(pu);
				return true;
				
			case DROPITEM:
				MainScreen.writeToConsole("Drop Item added to the mission", Color.RED);
				DropItemAction dr = new DropItemAction();
				um.addAction(dr);
				return true;
				
			case USEITEM:
				MainScreen.writeToConsole("Use Item added to the mission", Color.RED);
				UseItem ui = new UseItem();
				um.addAction(ui);
				return true;
				
			case HEALUNIT:
				MainScreen.writeToConsole("Heal Unit added to the mission", Color.RED);
				HealUnit hua = new HealUnit();
				um.addAction(hua);
				return true;
				
			case OBSERVE:
				melState = MISSIONFREEROAMSTATE;
				MainScreen.writeToConsole("Now move the cursor to target for Observe", Color.RED);
				return true;
				
			case REMOVETRAP:
				melState = MISSIONFREEROAMSTATE;
				MainScreen.writeToConsole("Now move the cursor to target for Remove Trap", Color.RED);
				return true;
			
			case SETTRAP:
				Trap t = new Trap();
				um.addAction(t);
				MainScreen.writeToConsole("Set Trap added to the mission", Color.RED);
				return true;
				
			case ATTACK:
				melState = MISSIONFREEROAMSTATE;
				MainScreen.writeToConsole("Now move the cursor to target for Attack", Color.RED);
				return true;
		}
		return false;
	}
	
	private boolean evalNormalState(ModelEvent e)
	{
		switch(ModelEventType.valueOf(e.getType()))
		{
			case TOGGLEMISSION:
					GameObject go = dh.getCurrentSelection();
					if(go.objectType() != GameObjectType.UNIT)
					{
						MainScreen.writeToConsole("Can only assign missions to unit", Color.RED);
						return true;
					}
					else
					{
						MainScreen.writeToConsole("Entering Assign Mission mode", Color.RED);
						um = new UnitMission(dh.getCurrentSelectionID());
						melState = MISSIONSTATE;
					}
				return true;
				
			case TOGGLEFREEROAM:
				MainScreen.writeToConsole("Entering Free Roam mode", Color.RED);
				melState = FREEROAMSTATE;
				return true;

			case SELECTNEXTUNIT:
				//MainScreen.writeToConsole(" Select Next Unit", Color.RED);
				NextUnit nu = new NextUnit(e.getPlayerID());
				nu.execute(dh);
				return true;
				
			case SELECTNEXTBASE:
				//MainScreen.writeToConsole(" Select Next Base", Color.RED);
				NextBase nb = new NextBase(e.getPlayerID());
				nb.execute(dh);
				return true;
				
			case NEXTTURN:
				MainScreen.writeToConsole(" Player " + e.getPlayerID() + " Begin Next Turn", Color.RED);
				NewTurn nt = new NewTurn(e.getPlayerID());
				nt.execute(dh);
				return true;
				
			case MOVEN:
				//MainScreen.writeToConsole(" Move Unit North", Color.RED);
				Move mn = new Move(MoveDirection.N);
				mn.execute(dh);
				return true;
				
			case MOVENW:
				//MainScreen.writeToConsole(" Move Unit Northwest", Color.RED);
				Move mnw = new Move(MoveDirection.NW);
				mnw.execute(dh);
				return true;
			
			case MOVEW:
				//MainScreen.writeToConsole(" Move Unit West", Color.RED);
				Move mw = new Move(MoveDirection.W);
				mw.execute(dh);
				return true;
				
			case MOVESW:
				//MainScreen.writeToConsole(" Move Unit Southwest", Color.RED);
				Move msw = new Move(MoveDirection.SW);
				msw.execute(dh);
				return true;
				
			case MOVES:
				//MainScreen.writeToConsole(" Move Unit South", Color.RED);
				Move ms = new Move(MoveDirection.S);
				ms.execute(dh);
				return true;
				
			case MOVESE:
				//MainScreen.writeToConsole(" Move Unit Southeast", Color.RED);
				Move mse = new Move(MoveDirection.SE);
				mse.execute(dh);
				return true;
				
			case MOVEE:
				//MainScreen.writeToConsole(" Move Unit East", Color.RED);
				Move me = new Move(MoveDirection.E);
				me.execute(dh);
				return true;
			
			case MOVENE:
				//MainScreen.writeToConsole(" Move Unit Northeast", Color.RED);
				Move mne = new Move(MoveDirection.NE);
				mne.execute(dh);
				return true;

			case UNITDOESNOTHING:
				//TODO:  Add unitdoesnothing action
				//MainScreen.writeToConsole(" Unit Does Nothing", Color.RED);
				return true;
				
			case PICKUPITEM:
				//MainScreen.writeToConsole("Pickup Item", Color.RED);
				PickupItemAction pu = new PickupItemAction();
				pu.execute(dh);
				return true;
				
			case DROPITEM:
				//MainScreen.writeToConsole(" Drop Item", Color.RED);
				DropItemAction dr = new DropItemAction();
				dr.execute(dh);
				return true;
				
			case USEITEM:
				//MainScreen.writeToConsole(" Use Item", Color.RED);
				UseItem ui=new UseItem();
				ui.execute(dh);
				return true;
				
			case BUILDCOLONIST:
				//MainScreen.writeToConsole(" Build Colonist", Color.RED);
				BuildUnit bc = new BuildUnit(UnitType.COLONIST, e.getPlayerID());
				bc.execute(dh);
				return true;
				
			case BUILDEXPLORER:
				//MainScreen.writeToConsole(" Build Explorer", Color.RED);
				BuildUnit be = new BuildUnit(UnitType.EXPLORER, e.getPlayerID());
				be.execute(dh);
				return true;
				
			case BUILDMELEE:
				//MainScreen.writeToConsole(" Build Melee", Color.RED);
				BuildUnit bm = new BuildUnit(UnitType.MELEE, e.getPlayerID());
				bm.execute(dh);
				return true;
				
			case BUILDRANGED:
				//MainScreen.writeToConsole(" Build Ranged", Color.RED);
				BuildUnit br = new BuildUnit(UnitType.RANGED, e.getPlayerID());
				br.execute(dh);return true;
				
			case BUILDBASE:
				//MainScreen.writeToConsole(" Build Base", Color.RED);
				BuildBase bb = new BuildBase(e.getPlayerID());
				bb.execute(dh);
				return true;
				
			case HEALUNIT:
				//MainScreen.writeToConsole(" Heal Unit", Color.RED);
				HealUnit hua = new HealUnit();
				hua.execute(dh);
				return true;
				
			case SNEAK:
				//MainScreen.writeToConsole(" Use Skill: Sneak", Color.RED);
				Sneak s = new Sneak();
				s.execute(dh);
				return true;
				
			case OBSERVE:
				melState = FREEROAMSTATE;
				MainScreen.writeToConsole("Now move the cursor to target for Observe", Color.RED);
				return true;
				
			case REMOVETRAP:
				melState = FREEROAMSTATE;
				MainScreen.writeToConsole("Now move the cursor to target for Remove Trap", Color.RED);
				return true;
				
			case SETTRAP:
				Trap t = new Trap();
				t.execute(dh);
				//MainScreen.writeToConsole(" Set Trap", Color.RED);
				return true;
				
			case SELECTRESEARCHTECH:
				ChangeCurrentResearch c = new ChangeCurrentResearch(e.getPlayerID());
				c.execute(dh);
				return true;
				
			case ATTACK:
				melState = FREEROAMSTATE;
				MainScreen.writeToConsole("Now move the cursor to target for Attack", Color.RED);
				return true;
		
			case MAKEARMY:
				//MainScreen.writeToConsole("Make Army", Color.RED);

				ObjectID[] objids = source.view.ViewData.getSelectedObjectIDS();
				Unit[] units = new Unit[objids.length];
				int unitsind = 0;
				for(ObjectID objid : objids){
					units[unitsind] = (Unit)(dh.objectQuery(objid));
					unitsind ++;
				}

				MakeArmy ma = new MakeArmy(units, e.getPlayerID());
				ma.execute(dh);
				return true;
 			}
		return false;
	}
	
}
